/*!
 *
 * This program is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License, version 2 as published by the Free Software
 * Foundation.
 *
 * You should have received a copy of the GNU General Public License along with this
 * program; if not, you can obtain a copy at http://www.gnu.org/licenses/gpl-2.0.html
 * or from the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 *
 * Copyright (c) 2002-2018 Hitachi Vantara. All rights reserved.
 *
 */

package org.pentaho.platform.uifoundation.chart;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.pentaho.platform.api.engine.IActionSequenceResource;
import org.pentaho.platform.api.engine.IPentahoRequestContext;
import org.pentaho.platform.api.engine.IPentahoUrlFactory;
import org.pentaho.platform.api.repository2.unified.RepositoryFilePermission;
import org.pentaho.platform.engine.core.solution.ActionInfo;
import org.pentaho.platform.engine.core.system.PentahoRequestContextHolder;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.pentaho.platform.engine.services.SolutionURIResolver;
import org.pentaho.platform.engine.services.actionsequence.ActionSequenceResource;
import org.pentaho.platform.uifoundation.component.xml.XmlComponent;
import org.pentaho.platform.uifoundation.messages.Messages;
import org.pentaho.platform.util.messages.LocaleHelper;
import org.pentaho.platform.util.xml.XMLParserFactoryProducer;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.List;

/**
 * This class is a Hitachi Vantara user interface component.
 * <p/>
 * It generates dial images that can be embedded into JSPs, portals or other HTML supporting user interface.
 * <p/>
 * <ol>
 * <li>The creating object sets the width, height, the type of the dial, and the name of the dial.xml file that
 * contains the definition of the dial.</li>
 * <li>This class creates an instance of a DialWidgetDefinition using the specified XML definition file. The XML
 * files are located in the solution folders and have .dial.xml extenstions. The dial XML files define the
 * attributes that define how the dial looks.</li>
 * <li>It uses the JFreeChartEngine to create an image of the dial.</li>
 * <li>Once the image has been created this class creates an XML document describing the dial
 * <li>It uses an XSL to tranforms the XML description into HTML.
 * </ol>
 * This is an example image
 */
public class DashboardWidgetComponent extends XmlComponent {

  /**
   * 
   */
  private static final long serialVersionUID = 3060729271469984040L;

  public static final int TYPE_DIAL = 1;

  public static final int TYPE_THERMOMETER = 2;

  private static final Log logger = LogFactory.getLog( DashboardWidgetComponent.class );

  private int type;

  private double value = DashboardWidgetComponent.TYPE_DIAL;

  private String definitionPath;

  private String title = ""; //$NON-NLS-1$

  private String units = ""; //$NON-NLS-1$

  private int width;

  private int height;

  /**
   * Creates a DashboardWidgetComponent.
   * <p>
   * After creating an instance of this class <CODE>validate</CODE> should be called.
   * 
   * @param type
   *          The type of the widget, currently only TYPE_DIAL is supported
   * @param definitionPath
   *          The path and name of the XML definition of the dial
   * @param width
   *          The width of the image to be created
   * @param height
   *          The height of the image to be created
   * @param urlFactory
   *          The urlFactory for the content
   * @param messages
   *          The messages list for any logger messages
   */
  public DashboardWidgetComponent( final int type, final String definitionPath, final int width, final int height,
      final IPentahoUrlFactory urlFactory, final List messages ) {
    super( urlFactory, messages, null );
    this.type = type;
    this.definitionPath = definitionPath;
    this.width = width;
    this.height = height;
    ActionInfo info = ActionInfo.parseActionString( definitionPath );
    if ( info != null ) {
      setSourcePath( info.getSolutionName() + File.separator + info.getPath() );
    }
    // Set the XSL file to be used to generate the HTML
    setXsl( "text/html", "DialWidget.xsl" ); //$NON-NLS-1$ //$NON-NLS-2$
  }

  /**
   * Sets the value to be displayed by the dial.
   * 
   * @param value
   *          The dial value
   */
  public void setValue( final double value ) {
    this.value = value;
  }

  /**
   * Sets the title for the dial
   * 
   * @param title
   *          The title of the dial
   */
  public void setTitle( final String title ) {
    this.title = title;
  }

  /**
   * Sets the unit for the dial value
   * 
   * @param units
   *          The dial units
   */
  public void setUnits( final String units ) {
    this.units = units;
  }

  /**
   * Gets the logger for his component.
   * 
   * @return logger This component's logger
   */
  @Override
  public Log getLogger() {
    return DashboardWidgetComponent.logger;
  }

  /**
   * Validate that this component can generate the requested dial
   */
  @Override
  public boolean validate() {
    // TODO
    return true;
  }

  /**
   * Create a dial image.
   * <ul>
   * <li>Load the specified XML document describing the dial definition</li>
   * <li>Create a dial definition object from the XML definition</li>
   * <li>Use the JFreeChartEngine to create a dial image</li>
   * <li>Create an XML document describing the dial</li>
   * <li>Return the XML document</li>
   * </ul>
   * 
   * @return The XML document describing this dial
   */
  @Override
  public Document getXmlContent() {

    WidgetDefinition widget = null;
    if ( type == DashboardWidgetComponent.TYPE_DIAL ) {

      // load the XML document that defines the dial
      IActionSequenceResource resource =
          new ActionSequenceResource( title, IActionSequenceResource.SOLUTION_FILE_RESOURCE, "text/xml", //$NON-NLS-1$
              definitionPath );
      Document dialDefinition = null;
      try {
        org.dom4j.io.SAXReader reader = XMLParserFactoryProducer.getSAXReader( new SolutionURIResolver() );
        dialDefinition =
            reader.read( resource.getInputStream( RepositoryFilePermission.READ, LocaleHelper.getLocale() ) );
      } catch ( Throwable t ) {
        // XML document can't be read. We'll just return a null document.
      }

      if ( dialDefinition == null ) {
        error( Messages.getInstance().getErrorString( "Widget.ERROR_0002_INVALID_RESOURCE", definitionPath ) ); //$NON-NLS-1$
        return null;
      }
      // create a dial definition from the XML definition
      widget = new DialWidgetDefinition( dialDefinition, 0, width, height, getSession() );

      if ( widget != null ) {
        // set the value to be displayed on the dial
        widget.setValue( new Double( value ) );

      }
    }
    /*
     * else if( type == TYPE_THERMOMETER ) { // load the XML document that defines the thermometer
     * 
     * ActionResource resource = new ActionResource( title, IActionResource.SOLUTION_FILE_RESOURCE, "text/xml",
     * //$NON-NLS-1$ PentahoSystem.getApplicationContext().getSolutionPath( definitionPath ) ); //$NON-NLS-1$
     * Document thermometerDefinition = null; try { thermometerDefinition = PentahoSystem.getResourceAsDocument(
     * resource ); } catch (IOException e) {} // create a dial definition from the XML definition widget =
     * createThermometer( thermometerDefinition );
     * 
     * if( widget != null ) { // set the value to be displayed on the dial widget.setValue( new Double(value) ); //
     * Set the XSL file to be used to generate the HTML setXsl( "text/html", "DialWidget.xsl" ); //$NON-NLS-1$
     * //$NON-NLS-2$ } else { error( Messages.getInstance().getString("Widget.ERROR_0001_COULD_NOT_CREATE") );
     * //$NON-NLS-1$ return null; } }
     */
    if ( widget == null ) {
      error( Messages.getInstance().getString( "Widget.ERROR_0001_COULD_NOT_CREATE" ) ); //$NON-NLS-1$
      return null;
    }
    // create an image for the dial using the JFreeChart engine
    StringWriter stringWriter = new StringWriter();
    PrintWriter printWriter = new PrintWriter( stringWriter );
    // create temporary file names
    String solutionDir = "system/tmp/"; //$NON-NLS-1$
    String fileNamePrefix = "tmp_pie_"; //$NON-NLS-1$
    String extension = ".png"; //$NON-NLS-1$
    String fileName = null;
    String filePathWithoutExtension = null;
    try {
      File file = PentahoSystem.getApplicationContext().createTempFile( getSession(), fileNamePrefix, extension, true );
      fileName = file.getName();
      filePathWithoutExtension = solutionDir + fileName.substring( 0, fileName.indexOf( '.' ) );
    } catch ( IOException e ) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    String dialTitle = ""; //$NON-NLS-1$
    JFreeChartEngine.saveChart( widget, dialTitle, units, filePathWithoutExtension, width, height,
        JFreeChartEngine.OUTPUT_PNG, printWriter, this );

    // Create a document that describes the result
    Document result = DocumentHelper.createDocument();
    IPentahoRequestContext requestContext = PentahoRequestContextHolder.getRequestContext();
    setXslProperty( "baseUrl", requestContext.getContextPath() ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    setXslProperty( "fullyQualifiedServerUrl", PentahoSystem.getApplicationContext().getFullyQualifiedServerURL() ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    Element root = result.addElement( "widget" ); //$NON-NLS-1$
    root.addElement( "title" ).setText( title ); //$NON-NLS-1$
    root.addElement( "units" ).setText( units ); //$NON-NLS-1$
    root.addElement( "width" ).setText( Integer.toString( width ) ); //$NON-NLS-1$
    root.addElement( "height" ).setText( Integer.toString( height ) ); //$NON-NLS-1$
    Element valueNode = root.addElement( "value" ); //$NON-NLS-1$
    valueNode.setText( Double.toString( value ) );
    valueNode.addAttribute( "in-image", Boolean.toString( widget.getValueFont() != null ) ); //$NON-NLS-1$
    root.addElement( "image" ).setText( fileName ); //$NON-NLS-1$
    return result;

  }

  public void dispose() {

  }

}
